// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:typed_data';

import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/src/summary/api_signature.dart';
import 'package:lpg2/lpg2.dart';
/// Return the bytes of the unlinked API signature of the given [unit].
///
/// If API signatures of two units are different, they may have different APIs.
Uint8List computeUnlinkedApiSignature(CompilationUnit unit) {
  var computer = _UnitApiSignatureComputer();
  computer.compute(unit);
  return computer.signature.toByteList();
}

class _UnitApiSignatureComputer {

  static const int _kindFieldDeclaration = 2;
  static const int _kindMethodDeclaration = 3;
  static const int _nullNode = 0;
  static const int _notNullNode = 1;
  static const int _nullToken = 0;
  static const int _notNullToken = 1;

  final ApiSignature signature = ApiSignature();

  void compute(CompilationUnit unit) {
    signature.addFeatureSet(unit.featureSet);
    unit.nodes.forEach(_addNode);
  }



  void _addNode(AstNode? node) {
    if (node != null) {
      signature.addInt(_notNullNode);
      _addTokens(node.leftIToken, node.getRightIToken());
    } else {
      signature.addInt(_nullNode);
    }
  }

  void _addToken(IToken? token) {
    if (token != null) {
      signature.addInt(_notNullToken);
      signature.addString(token.toString());
    } else {
      signature.addInt(_nullToken);
    }
  }

  /// Appends tokens from [begin] (including), to [end] (also including).
  void _addTokens(IToken begin, IToken end) {
    var tokenStream = begin.getILexStream()?.getIPrsStream();
    if(null == tokenStream)
      return;

    IToken? token = begin;
    while (token != null) {
      _addToken(token);

      if (token == end) {
        break;
      }
      var nextToken = tokenStream.getIToken(token.getTokenIndex()+1);

      // Stop if EOF.
      if (nextToken == token) {
        break;
      }
      token = nextToken;
    }
  }
}
